package org.hsieh.tr.explore.ui;

import java.sql.Driver;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.hsieh.tr.explore.db.spi.IDriverListener;
import org.hsieh.tr.explore.db.spi.IDriverProvider;
import org.hsieh.tr.explore.util.JarUtil;
import org.hsieh.tr.explore.util.StringUtil;

@SuppressWarnings("unchecked")
public class ClasspathTableComposite extends Composite implements
	IDriverProvider {

    private ListViewer viewer;
    private Button addButton;
    private Button removeButton;

    private List<IDriverListener> listeners = new ArrayList<IDriverListener>();

    private List<String> classpathes = new ArrayList<String>();

    public List<String> getClasspathes() {
	return Collections.unmodifiableList(classpathes);
    }

    public ClasspathTableComposite(Composite parent, int style) {
	super(parent, style);
	createControls();
    }

    public void addClassPath(String classPath) {
	if (!StringUtil.isNullOrEmpty(classPath))
	    if (!classpathes.contains(classPath))
		classpathes.add(classPath);
    }

    public void addClassPathes(List<String> classPathes) {
	if (classPathes != null && !classPathes.isEmpty()) {
	    for (String path : classPathes) {
		addClassPath(path);
	    }
	}
    }

    private void createControls() {
	GridLayoutFactory.swtDefaults().numColumns(2).margins(0, 0).applyTo(
		this);

	viewer = createListViewrAndLayout();
	setContentLabelProvider(viewer);

	viewer.setInput(classpathes);

	createActionButton();
    }

    private void createActionButton() {
	addButton = new Button(this, SWT.NONE);
	addButton.setText("Add...");
	addButton.addSelectionListener(new SelectionAdapter() {

	    @Override
	    public void widgetSelected(SelectionEvent e) {
		FileDialog dialog = new FileDialog(ClasspathTableComposite.this
			.getShell(), SWT.OPEN);
		dialog.setFilterExtensions(new String[] { "*.jar" });
		dialog.setText("Select driver library");
		final String classpath = dialog.open();
		if (classpath == null || classpath.equals("")) {
		    return;
		}
		classpathes.add(classpath);
		BusyIndicator.showWhile(getDisplay(), new Runnable() {
		    public void run() {
			whenFind(findDriverClassInJar(classpath));
		    }
		});
		refreshList();
	    }
	});

	GridData data = new GridData();
	data.horizontalAlignment = SWT.FILL;
	addButton.setLayoutData(data);

	removeButton = new Button(this, SWT.NONE);
	removeButton.setText("Remove");
	GridData gridData = new GridData();
	gridData.verticalAlignment = SWT.BEGINNING;
	removeButton.setLayoutData(gridData);

	removeButton.addSelectionListener(new SelectionAdapter() {

	    @Override
	    public void widgetSelected(SelectionEvent e) {
		IStructuredSelection selection = (IStructuredSelection) viewer
			.getSelection();
		if (selection == null || selection.isEmpty()) {
		    return;
		}
		for (Iterator<?> iter = selection.iterator(); iter.hasNext();) {
		    String classpath = (String) iter.next();
		    classpathes.remove(classpath);
		}
		refreshList();
	    }

	});
    }

    protected List<Class<Driver>> findDriverClassInJar(String classpath) {
	return JarUtil.findDriverInJar(classpath);
    }

    public void refreshList() {
	viewer.refresh();
    }

    private ListViewer createListViewrAndLayout() {
	ListViewer viewer = new ListViewer(this, SWT.BORDER);
	GridData layoutData = new GridData(GridData.FILL_BOTH);
	layoutData.verticalSpan = 2;
	viewer.getList().setLayoutData(layoutData);
	return viewer;
    }

    private void setContentLabelProvider(ListViewer viewer) {
	viewer.setContentProvider(new IStructuredContentProvider() {

	    public Object[] getElements(Object inputElement) {
		if (inputElement instanceof List) {
		    return ((List) inputElement).toArray(new Object[0]);
		}
		return null;
	    }

	    public void dispose() {

	    }

	    public void inputChanged(Viewer viewer, Object oldInput,
		    Object newInput) {
	    }
	});

	viewer.setLabelProvider(new ILabelProvider() {

	    public Image getImage(Object element) {
		return null;
	    }

	    public String getText(Object element) {
		return element.toString();
	    }

	    public void addListener(ILabelProviderListener listener) {

	    }

	    public void dispose() {

	    }

	    public boolean isLabelProperty(Object element, String property) {
		return false;
	    }

	    public void removeListener(ILabelProviderListener listener) {

	    }

	});
    }

    public <T extends Driver> void whenFind(List<Class<T>> klass) {
	if (klass == null || klass.isEmpty()) {
	    return;
	}
	if (listeners != null && !listeners.isEmpty()) {
	    for (IDriverListener listener : listeners) {
		listener.driversAreFound(klass);
	    }
	}
    }

    public void addDriverListener(IDriverListener listener) {
	if (listener == null)
	    throw new IllegalArgumentException("listern");
	if (!listeners.contains(listener)) {
	    listeners.add(listener);
	}

    }

    public void removeDriverListener(IDriverListener listener) {
	listeners.remove(listener);
    }
}
